package com.objectproject.main.dao;

import java.util.ArrayList;
import java.util.HashSet;

import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.objectproject.main.dao.iface.hierarchy.MyObjectHierarchyDAO;
import com.objectproject.main.dao.mybatis.mapper.hierarchy.MyObjectHierarchyMapper;
import com.objectproject.main.model.MyObject;

@Repository
public class MyObjectHierarchyDAOImpl implements MyObjectHierarchyDAO {

	
	@Autowired
	SqlSession sqlSession;
	
	//재귀적 쿼리 구현 완료되면 지울 것, 의미상 여기있으면 안되는 선언
	@Autowired
	MyObjectDAOImpl myObjectDAOImpl;
	
	
	
	@Override
	public ArrayList<Long> selectSuperObjectIds(long objectId) {
		return sqlSession.getMapper(MyObjectHierarchyMapper.class).selectSuperObjectIds(objectId);
	}

	@Override
	public ArrayList<Long> selectSubObjectIds(long objectId) {
		return sqlSession.getMapper(MyObjectHierarchyMapper.class).selectSubObjectIds(objectId);
	}

	@Override
	public ArrayList<Long> selectAncestorObjectIds(long objectId) {
		// sql 문장으로 해결하던가 그게 아니라면 여기에 로직을 구현하지 말 것
		// 일단 여기서 해결 나중에 맵퍼(mysql 내에서 이 문제가 해결된)를 사용하자.
		
		HashSet<Long> sumAncestorObjectIds = new HashSet<Long>();
		ArrayList<Long> readyQueue = new ArrayList<Long>();
		ArrayList<Long> tempObjectIds = new ArrayList<Long>();
		
		
		readyQueue.add(objectId);
		
		while(readyQueue.size() != 0){
			
			tempObjectIds = sqlSession.getMapper(MyObjectHierarchyMapper.class).selectSuperObjectIds(readyQueue.get(0));
			
			readyQueue.addAll(tempObjectIds);
			sumAncestorObjectIds.addAll(tempObjectIds);
			
			
			readyQueue.remove(0);
		
		}
		
		return new ArrayList<Long>(sumAncestorObjectIds);
	}

	@Override
	public ArrayList<Long> selectDescendantObjectIds(long objectId) {
		// sql 문장으로 해결하던가 그게 아니라면 여기에 로직을 구현하지 말 것
		// 일단 여기서 해결 나중에 맵퍼(mysql 내에서 이 문제가 해결된)를 사용하자.
		
		HashSet<Long> sumDescendantObjectIds = new HashSet<Long>();
		ArrayList<Long> readyQueue = new ArrayList<Long>();
		ArrayList<Long> tempObjectIds = new ArrayList<Long>();
		
		
		readyQueue.add(objectId);
		
		while(readyQueue.size() != 0){
			
			tempObjectIds = sqlSession.getMapper(MyObjectHierarchyMapper.class).selectSubObjectIds(readyQueue.get(0));
			
			readyQueue.addAll(tempObjectIds);
			sumDescendantObjectIds.addAll(tempObjectIds);
			
			
			readyQueue.remove(0);
		
		}
		
		return new ArrayList<Long>(sumDescendantObjectIds);
		
	}
	
	@Override
	public ArrayList<Long> selectLeafObjectIds(long objectId) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public ArrayList<Long> selectFinalObjectIds(long objectId) {
		// sql 문장으로 해결하던가 그게 아니라면 여기에 로직을 구현하지 말 것
		// 일단 여기서 해결 나중에 맵퍼(mysql 내에서 이 문제가 해결된)를 사용하자.
		
		ArrayList<Long> objectIds = selectDescendantObjectIds(objectId);
		
		ArrayList<Long> resultObjectIds = new ArrayList<Long>();
		MyObject currentObject = null;
		
		for(int i = 0 ; i < objectIds.size() ; i++){
			currentObject = myObjectDAOImpl.selectMyObjectById(objectIds.get(i));
			if(currentObject.isFinal() == true)
				resultObjectIds.add(currentObject.getObjectId());
		}
		
		return resultObjectIds;
	}
	
	@Override
	public ArrayList<Long> selectInterfaceObjectIds(long objectId) {
		// sql 문장으로 해결하던가 그게 아니라면 여기에 로직을 구현하지 말 것
		// 일단 여기서 해결 나중에 맵퍼(mysql 내에서 이 문제가 해결된)를 사용하자.
		return null;
	}
	
	
	
	public ArrayList<MyObject> selectSuperObjects(long objectId) {
		return sqlSession.getMapper(MyObjectHierarchyMapper.class).selectSuperObjects(objectId);
	}

	@Override
	public ArrayList<MyObject> selectSubObjects(long objectId) {
		return sqlSession.getMapper(MyObjectHierarchyMapper.class).selectSubObjects(objectId);
	}

	@Override
	public ArrayList<MyObject> selectAncestorObjects(long objectId) {
		//임시로 쓰는 구현
		ArrayList<Long> ancestorObjectIds = selectAncestorObjectIds(objectId);
		
		return convertEasy(ancestorObjectIds);
	}

	@Override
	public ArrayList<MyObject> selectDescendantObjects(long objectId) {
		ArrayList<Long> descendantObjectIds = selectDescendantObjectIds(objectId);
		
		return convertEasy(descendantObjectIds);	
	}
	
	@Override
	public ArrayList<MyObject> selectLeafObjects(long objectId) {
		
		return null;
	}

	@Override
	public ArrayList<MyObject> selectFinalObjects(long objectId) {
		return null;
	}
	
	@Override
	public ArrayList<MyObject> selectInterfaceObjects(long objectId) {
		return null;
	}
	
	

	
	@Override
	public void insertHierarchy(long objectId, long superObjectId) {
		sqlSession.getMapper(MyObjectHierarchyMapper.class).insertHierarchy(objectId, superObjectId);
		MyObject myObject = myObjectDAOImpl.selectMyObjectById(objectId);
		MyObject superObject = myObjectDAOImpl.selectMyObjectById(superObjectId);
		
		int currentDepth = myObject.getDepth();
		int superDepth = superObject.getDepth();
		
		if(superDepth > currentDepth || superDepth == 0){
			myObject.setDepth(superDepth + 1);
			myObjectDAOImpl.updateMyObject(myObject);
		}
		
		//return sqlSession.getMapper(MyObjectMapper.class).selectMyObjectById(objectId);

	}

	@Override
	public void deleteHierarchy(long objectId, long superObjectId) {
		sqlSession.getMapper(MyObjectHierarchyMapper.class).deleteHierarchy(objectId, superObjectId);
	}

	
	//helper
	private ArrayList<MyObject> convertEasy(ArrayList<Long> myObjectIds){
		ArrayList<MyObject> myObjects = new ArrayList<MyObject>();
		for(Long currentLong:myObjectIds){
			myObjects.add(myObjectDAOImpl.selectMyObjectById(currentLong));
		}
		return myObjects;
	}

}
